//############################################################################
//## WiiDS Emulator (DeSmuME Port)
//##--------------------------------------------------------------------------
//## menu.cpp
//## - Menu Flow Logic
//############################################################################

#include <gccore.h>
#include <ogcsys.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <wiiuse/wpad.h>
#include <di/di.h>

#include "filebrowser.h"
#include "filelist.h"
#include "fileop.h"
#include "gui/gui.h"
#include "input.h"
#include "menu.h"
#include "networkop.h"
#include "preferences.h"
#include "wiids.h"

#define THREAD_SLEEP 100

static GuiImageData * pointer[4];
static GuiText * version = NULL;
static GuiButton * btnLogo = NULL;
static GuiImage * bgImg = NULL;
static GuiImage * bgTopImg = NULL;
static GuiImage * bgBottomImg = NULL;
static GuiSound * bgMusic = NULL;
static GuiSound * enterSound = NULL;
static GuiSound * exitSound = NULL;
static GuiWindow * mainWindow = NULL;
static int lastMenu = MENU_NONE;
static lwp_t guithread = LWP_THREAD_NULL;
static lwp_t progressthread = LWP_THREAD_NULL;
static lwp_t updatethread = LWP_THREAD_NULL;
static int showProgress = 0;
static char progressTitle[100];
static char progressMsg[200];
static int progressDone = 0;
static int progressTotal = 0;
static bool guiHalt = true;

//----------------------------------------------------------------------------
// MENU - ResumeGui
//----------------------------------------------------------------------------
static void ResumeGui()
{
	guiHalt = false;
	LWP_ResumeThread (guithread);
}

//----------------------------------------------------------------------------
// MENU - HaltGui
//----------------------------------------------------------------------------
static void HaltGui()
{
	guiHalt = true;
	while(!LWP_ThreadIsSuspended(guithread))
		usleep(THREAD_SLEEP);
}

//----------------------------------------------------------------------------
// MENU - ResetText
//----------------------------------------------------------------------------
//void ResetText()
//{
//	LoadLanguage();
//	if(mainWindow)
//		mainWindow->ResetText();
//}

//----------------------------------------------------------------------------
// MENU - WindowPrompt
//----------------------------------------------------------------------------
int WindowPrompt(const char *title, const char *msg, const char *btn1Label, const char *btn2Label)
{
	int choice = -1;

	GuiWindow promptWindow(448,288);
	promptWindow.SetAlignment(ALIGN_CENTRE, ALIGN_MIDDLE);
	promptWindow.SetPosition(0, -10);
	GuiSound btnSoundOver(button_over_pcm, button_over_pcm_size, SOUND_PCM);
	GuiSound btnSoundClick(button_click_pcm, button_click_pcm_size, SOUND_PCM);
	GuiImageData btnOutline(button_png);
	GuiImageData btnOutlineOver(button_over_png);

	GuiTrigger trigA;
	trigA.SetSimpleTrigger(-1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A);

	GuiImageData dialogBox(dialogue_box_png);
	GuiImage dialogBoxImg(&dialogBox);

	GuiText titleTxt(title, 26, (GXColor){0, 0, 0, 255});
	titleTxt.SetAlignment(ALIGN_CENTRE, ALIGN_TOP);
	titleTxt.SetPosition(0,14);

	GuiText msgTxt(msg, 26, (GXColor){0, 0, 0, 255});
	msgTxt.SetAlignment(ALIGN_CENTRE, ALIGN_MIDDLE);
	msgTxt.SetPosition(0,-20);
	msgTxt.SetWrap(true, 430);

	GuiText btn1Txt(btn1Label, 24, (GXColor){0, 0, 0, 255});
	GuiImage btn1Img(&btnOutline);
	GuiImage btn1ImgOver(&btnOutlineOver);
	GuiButton btn1(btnOutline.GetWidth(), btnOutline.GetHeight());
	if(btn2Label)
	{
		btn1.SetAlignment(ALIGN_LEFT, ALIGN_BOTTOM);
		btn1.SetPosition(20, -25);
	}
	else
	{
		btn1.SetAlignment(ALIGN_CENTRE, ALIGN_BOTTOM);
		btn1.SetPosition(0, -25);
	}
	btn1.SetLabel(&btn1Txt);
	btn1.SetImage(&btn1Img);
	btn1.SetImageOver(&btn1ImgOver);
	btn1.SetSoundOver(&btnSoundOver);
	btn1.SetSoundClick(&btnSoundClick);
	btn1.SetTrigger(&trigA);
	btn1.SetState(STATE_SELECTED);
	btn1.SetEffectGrow();

	GuiText btn2Txt(btn2Label, 24, (GXColor){0, 0, 0, 255});
	GuiImage btn2Img(&btnOutline);
	GuiImage btn2ImgOver(&btnOutlineOver);
	GuiButton btn2(btnOutline.GetWidth(), btnOutline.GetHeight());
	btn2.SetAlignment(ALIGN_RIGHT, ALIGN_BOTTOM);
	btn2.SetPosition(-20, -25);
	btn2.SetLabel(&btn2Txt);
	btn2.SetImage(&btn2Img);
	btn2.SetImageOver(&btn2ImgOver);
	btn2.SetSoundOver(&btnSoundOver);
	btn2.SetSoundClick(&btnSoundClick);
	btn2.SetTrigger(&trigA);
	btn2.SetEffectGrow();

	promptWindow.Append(&dialogBoxImg);
	promptWindow.Append(&titleTxt);
	promptWindow.Append(&msgTxt);
	promptWindow.Append(&btn1);
	if(btn2Label)
		promptWindow.Append(&btn2);

	promptWindow.SetEffect(EFFECT_SLIDE_TOP | EFFECT_SLIDE_IN, 50);
	CancelAction();

	HaltGui();

	mainWindow->SetState(STATE_DISABLED);
	mainWindow->Append(&promptWindow);
	mainWindow->ChangeFocus(&promptWindow);

	if(btn2Label)
	{
		btn1.ResetState();
		btn2.SetState(STATE_SELECTED);
	}

	ResumeGui();

	while(choice == -1)
	{
		usleep(THREAD_SLEEP);

		if(btn1.GetState() == STATE_CLICKED)
			choice = 1;
		else if(btn2.GetState() == STATE_CLICKED)
			choice = 0;
	}

	promptWindow.SetEffect(EFFECT_SLIDE_TOP | EFFECT_SLIDE_OUT, 50);
	while(promptWindow.GetEffect() > 0) usleep(THREAD_SLEEP);

	HaltGui();

	mainWindow->Remove(&promptWindow);
	mainWindow->SetState(STATE_DEFAULT);

	ResumeGui();

	return choice;
}

//----------------------------------------------------------------------------
// MENU - ErrorPrompt
//----------------------------------------------------------------------------
void ErrorPrompt(const char *msg)
{
	WindowPrompt("Error", msg, "OK", NULL);
}

//----------------------------------------------------------------------------
// MENU - ErrorPromptRetry
//----------------------------------------------------------------------------
int ErrorPromptRetry(const char *msg)
{
	return WindowPrompt("Error", msg, "Retry", "Cancel");
}

//----------------------------------------------------------------------------
// MENU - InfoPrompt
//----------------------------------------------------------------------------
void InfoPrompt(const char *msg)
{
	WindowPrompt("Information", msg, "OK", NULL);
}

//----------------------------------------------------------------------------
// MENU - EmulatorUpdate
//----------------------------------------------------------------------------
static void * EmulatorUpdate (void *arg)
{
	bool installUpdate = WindowPrompt("Update","An update is available!","Update","Ignore");
	if(installUpdate)
		if(DownloadUpdate())
			ExitRequested = 1;
	return NULL;
}

//----------------------------------------------------------------------------
// MENU - UpdateGui
//----------------------------------------------------------------------------
static void * UpdateGUI (void *arg)
{
	int i;

	while(1)
	{
		if(guiHalt)
		{
			LWP_SuspendThread(guithread);
		}
		else
		{
			UpdatePads();
			mainWindow->Draw();

			for(i=3; i >= 0; i--)
			{
				if(userInput[i].wpad->ir.valid)
					Menu_DrawImg(userInput[i].wpad->ir.x-48, userInput[i].wpad->ir.y-48,
					96, 96, pointer[i]->GetImage(), userInput[i].wpad->ir.angle, 1, 1, 255);
				DoRumble(i);
			}

			Menu_Render();

			for(i=0; i < 4; i++)
				mainWindow->Update(&userInput[i]);

			if(updateFound)
			{
				updateFound = false;
//				if(!loadingFile)
					LWP_CreateThread (&updatethread, EmulatorUpdate, NULL, NULL, 0, 70);
			}

			if(ExitRequested || ShutdownRequested)
			{
				for(i = 0; i < 255; i += 15)
				{
					mainWindow->Draw();
					Menu_DrawRectangle(0,0,screenwidth,screenheight,(GXColor){0, 0, 0, i},1);
					Menu_Render();
				}
				ExitApp();
			}
		}
		usleep(THREAD_SLEEP);
	}
	return NULL;
}

//----------------------------------------------------------------------------
// MENU - ProgressWindow
//----------------------------------------------------------------------------
static int progsleep = 0;
static void ProgressWindow(char *title, char *msg)
{
	GuiWindow promptWindow(448,288);
	promptWindow.SetAlignment(ALIGN_CENTRE, ALIGN_MIDDLE);
	promptWindow.SetPosition(0, -10);
	GuiSound btnSoundOver(button_over_pcm, button_over_pcm_size, SOUND_PCM);
	GuiSound btnSoundClick(button_click_pcm, button_click_pcm_size, SOUND_PCM);
	GuiImageData btnOutline(button_png);
	GuiImageData btnOutlineOver(button_over_png);
	GuiTrigger trigA;
	trigA.SetSimpleTrigger(-1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A);

	GuiImageData dialogBox(dialogue_box_png);
	GuiImage dialogBoxImg(&dialogBox);

	GuiImageData progressbarOutline(progressbar_outline_png);
	GuiImage progressbarOutlineImg(&progressbarOutline);
	progressbarOutlineImg.SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE);
	progressbarOutlineImg.SetPosition(25, 40);

	GuiImageData progressbarEmpty(progressbar_empty_png);
	GuiImage progressbarEmptyImg(&progressbarEmpty);
	progressbarEmptyImg.SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE);
	progressbarEmptyImg.SetPosition(25, 40);
	progressbarEmptyImg.SetTile(100);

	GuiImageData progressbar(progressbar_png);
	GuiImage progressbarImg(&progressbar);
	progressbarImg.SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE);
	progressbarImg.SetPosition(25, 40);

	GuiImageData throbber(throbber_png);
	GuiImage throbberImg(&throbber);
	throbberImg.SetAlignment(ALIGN_CENTRE, ALIGN_MIDDLE);
	throbberImg.SetPosition(0, 40);

	GuiText titleTxt(title, 26, (GXColor){0, 0, 0, 255});
	titleTxt.SetAlignment(ALIGN_CENTRE, ALIGN_TOP);
	titleTxt.SetPosition(0,14);
	GuiText msgTxt(msg, 26, (GXColor){0, 0, 0, 255});
	msgTxt.SetAlignment(ALIGN_CENTRE, ALIGN_TOP);
	msgTxt.SetPosition(0,80);

	promptWindow.Append(&dialogBoxImg);
	promptWindow.Append(&titleTxt);
	promptWindow.Append(&msgTxt);
	if(showProgress == 1)
	{
		promptWindow.Append(&progressbarEmptyImg);
		promptWindow.Append(&progressbarImg);
		promptWindow.Append(&progressbarOutlineImg);
	}
	else
	{
		promptWindow.Append(&throbberImg);
	}

	progsleep = 400000;
	while(progsleep > 0)
	{
		if(!showProgress)
			break;
		usleep(THREAD_SLEEP);
		progsleep -= THREAD_SLEEP;
	}
	if(!showProgress)
		return;

	HaltGui();

	int oldState = mainWindow->GetState();
	mainWindow->SetState(STATE_DISABLED);
	mainWindow->Append(&promptWindow);
	mainWindow->ChangeFocus(&promptWindow);

	ResumeGui();

	float angle = 0;
	u32 count = 0;
	while(showProgress)
	{
		progsleep = 20000;
		while(progsleep > 0)
		{
			if(!showProgress)
				break;
			usleep(THREAD_SLEEP);
			progsleep -= THREAD_SLEEP;
		}
		if(showProgress == 1)
		{
			progressbarImg.SetTile(100*progressDone/progressTotal);
		}
		else if(showProgress == 2)
		{
			if(count % 5 == 0)
			{
				angle+=45.0f;
				if(angle >= 360.0f)
					angle = 0;
				throbberImg.SetAngle(angle);
			}
			++count;
		}
	}

	HaltGui();

	mainWindow->Remove(&promptWindow);
	mainWindow->SetState(oldState);

	ResumeGui();
}

//----------------------------------------------------------------------------
// MENU - ProgressThread
//----------------------------------------------------------------------------
static void * ProgressThread (void *arg)
{
	while(1)
	{
		if(!showProgress)
			LWP_SuspendThread (progressthread);
		ProgressWindow(progressTitle, progressMsg);
		usleep(THREAD_SLEEP);
	}
	return NULL;
}

//----------------------------------------------------------------------------
// MENU - ShowProgress
//----------------------------------------------------------------------------
void ShowProgress (const char *msg, int done, int total)
{
	if(!mainWindow || ExitRequested || ShutdownRequested)
		return;
	if(total < (256*1024))
		return;
	if(done > total) // this shouldn't happen
		done = total;
	if(showProgress != 1)
		CancelAction();
	strncpy(progressMsg, msg, 200);
	sprintf(progressTitle, "Please Wait...");
	showProgress = 1;
	progressTotal = total;
	progressDone = done;
	LWP_ResumeThread (progressthread);
}

//----------------------------------------------------------------------------
// MENU - ShowAction
//----------------------------------------------------------------------------
void ShowAction (const char *msg)
{
	if(!mainWindow || ExitRequested || ShutdownRequested)
		return;
	if(showProgress != 0)
		CancelAction();
	strncpy(progressMsg, msg, 200);
	sprintf(progressTitle, "Please Wait...");
	showProgress = 2;
	progressDone = 0;
	progressTotal = 0;
	LWP_ResumeThread (progressthread);
}

//----------------------------------------------------------------------------
// MENU - CancelAction
//----------------------------------------------------------------------------
void CancelAction()
{
	showProgress = 0;
	while(!LWP_ThreadIsSuspended(progressthread))
		usleep(THREAD_SLEEP);
}

//----------------------------------------------------------------------------
// MENU - InitGUIThreads
//----------------------------------------------------------------------------
void InitGUIThreads()
{
	LWP_CreateThread (&guithread, UpdateGUI, NULL, NULL, 0, 70);
	LWP_CreateThread (&progressthread, ProgressThread, NULL, NULL, 0, 40);
}

//----------------------------------------------------------------------------
// MENU - OnScreenKeyboard
//----------------------------------------------------------------------------
static void OnScreenKeyboard(char * var, u32 maxlen)
{
	int save = -1;

	GuiKeyboard keyboard(var, maxlen);

	GuiSound btnSoundOver(button_over_pcm, button_over_pcm_size, SOUND_PCM);
	GuiSound btnSoundClick(button_click_pcm, button_click_pcm_size, SOUND_PCM);
	GuiImageData btnOutline(button_png);
	GuiImageData btnOutlineOver(button_over_png);

	GuiTrigger trigA;
	trigA.SetSimpleTrigger(-1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A);

	GuiText okBtnTxt("OK", 24, (GXColor){0, 0, 0, 255});
	GuiImage okBtnImg(&btnOutline);
	GuiImage okBtnImgOver(&btnOutlineOver);
	GuiButton okBtn(btnOutline.GetWidth(), btnOutline.GetHeight());
	okBtn.SetAlignment(ALIGN_LEFT, ALIGN_BOTTOM);
	okBtn.SetPosition(25, -25);
	okBtn.SetLabel(&okBtnTxt);
	okBtn.SetImage(&okBtnImg);
	okBtn.SetImageOver(&okBtnImgOver);
	okBtn.SetSoundOver(&btnSoundOver);
	okBtn.SetSoundClick(&btnSoundClick);
	okBtn.SetTrigger(&trigA);
	okBtn.SetEffectGrow();

	GuiText cancelBtnTxt("Cancel", 24, (GXColor){0, 0, 0, 255});
	GuiImage cancelBtnImg(&btnOutline);
	GuiImage cancelBtnImgOver(&btnOutlineOver);
	GuiButton cancelBtn(btnOutline.GetWidth(), btnOutline.GetHeight());
	cancelBtn.SetAlignment(ALIGN_RIGHT, ALIGN_BOTTOM);
	cancelBtn.SetPosition(-25, -25);
	cancelBtn.SetLabel(&cancelBtnTxt);
	cancelBtn.SetImage(&cancelBtnImg);
	cancelBtn.SetImageOver(&cancelBtnImgOver);
	cancelBtn.SetSoundOver(&btnSoundOver);
	cancelBtn.SetSoundClick(&btnSoundClick);
	cancelBtn.SetTrigger(&trigA);
	cancelBtn.SetEffectGrow();

	keyboard.Append(&okBtn);
	keyboard.Append(&cancelBtn);

	HaltGui();

	mainWindow->SetState(STATE_DISABLED);
	mainWindow->Append(&keyboard);
	mainWindow->ChangeFocus(&keyboard);

	ResumeGui();

	while(save == -1)
	{
		usleep(THREAD_SLEEP);
		if(okBtn.GetState() == STATE_CLICKED)
			save = 1;
		else if(cancelBtn.GetState() == STATE_CLICKED)
			save = 0;
	}
	if(save)
	{
		snprintf(var, maxlen, "%s", keyboard.kbtextstr);
	}

	HaltGui();

	mainWindow->Remove(&keyboard);
	mainWindow->SetState(STATE_DEFAULT);

	ResumeGui();
}

//----------------------------------------------------------------------------
// MENU - WindowCredits
//----------------------------------------------------------------------------
static void WindowCredits(void * ptr)
{
	if(btnLogo->GetState() != STATE_CLICKED)
		return;
	btnLogo->ResetState();

	bool exit = false;
	int i = 0;
	int y = 20;

	GuiWindow creditsWindow(screenwidth,screenheight);
	GuiWindow creditsWindowBox(580,448);
	creditsWindowBox.SetAlignment(ALIGN_CENTRE, ALIGN_MIDDLE);

	GuiImageData creditsBox(credits_box_png);
	GuiImage creditsBoxImg(&creditsBox);
	creditsBoxImg.SetAlignment(ALIGN_CENTRE, ALIGN_MIDDLE);

	creditsWindowBox.Append(&creditsBoxImg);

	int numEntries = 22;
	GuiText * txt[numEntries];

	txt[i] = new GuiText("Credits", 30, (GXColor){0, 0, 0, 255});
	txt[i]->SetAlignment(ALIGN_CENTRE, ALIGN_TOP); txt[i]->SetPosition(0,y); i++; y+=32;
	txt[i] = new GuiText("Official Site: http://code.google.com/p/wiids/", 20, (GXColor){0, 0, 0, 255});
	txt[i]->SetAlignment(ALIGN_CENTRE, ALIGN_TOP); txt[i]->SetPosition(0,y); i++; y+=40;

	txt[i]->SetPresets(22, (GXColor){0, 0, 0, 255}, 0, FTGX_JUSTIFY_LEFT | FTGX_ALIGN_TOP, ALIGN_LEFT, ALIGN_TOP);

	txt[i] = new GuiText("Emulator Core Design");
	txt[i]->SetPosition(50,y); i++;
	txt[i] = new GuiText("Arikado, Scanff");
	txt[i]->SetPosition(320,y); i++; y+=24;
	txt[i] = new GuiText("Additional Core Work");
	txt[i]->SetPosition(50,y); i++;
	txt[i] = new GuiText("Dancinninjac, Profetylen");
	txt[i]->SetPosition(320,y); i++; y+=24;
	txt[i] = new GuiText("Menu Images/Design");
	txt[i]->SetPosition(50,y); i++;
	txt[i] = new GuiText("TehSeph, rvn920");
	txt[i]->SetPosition(320,y); i++; y+=24;
	txt[i] = new GuiText("Menu Music");
	txt[i]->SetPosition(50,y); i++;
	txt[i] = new GuiText("'Free Your Soul'");
	txt[i]->SetPosition(320,y); i++; y+=24;
	txt[i] = new GuiText("by JohnW");
	txt[i]->SetPosition(340,y); i++; y+=48;

	txt[i] = new GuiText("DeSmuME 0.9.5");
	txt[i]->SetPosition(50,y); i++;
	txt[i] = new GuiText("Yabause, Zeromus");
	txt[i]->SetPosition(320,y); i++; y+=24;
	txt[i] = new GuiText("libwiigui");
	txt[i]->SetPosition(50,y); i++;
	txt[i] = new GuiText("Tantric");
	txt[i]->SetPosition(320,y); i++; y+=24;
	txt[i] = new GuiText("devkitPPC/libogc");
	txt[i]->SetPosition(50,y); i++;
	txt[i] = new GuiText("Shagkur, Wintermute");
	txt[i]->SetPosition(320,y); i++; y+=24;
	txt[i] = new GuiText("FreeTypeGX");
	txt[i]->SetPosition(50,y); i++;
	txt[i] = new GuiText("Armin Tamzarian");
	txt[i]->SetPosition(320,y); i++; y+=48;

	txt[i]->SetPresets(18, (GXColor){0, 0, 0, 255}, 0, FTGX_JUSTIFY_CENTER | FTGX_ALIGN_TOP, ALIGN_CENTRE, ALIGN_TOP);

	txt[i] = new GuiText("This software is open source and may be copied,");
	txt[i]->SetPosition(0,y); i++; y+=20;
	txt[i] = new GuiText("distributed, or modified under the terms of the");
	txt[i]->SetPosition(0,y); i++; y+=20;
	txt[i] = new GuiText("GNU General Public License (GPL) Version 2.");
	txt[i]->SetPosition(0,y); i++; y+=20;

	for(i=0; i < numEntries; i++)
		creditsWindowBox.Append(txt[i]);
	creditsWindow.Append(&creditsWindowBox);

	while(!exit)
	{
		UpdatePads();

		bgImg->Draw();
		bgTopImg->Draw();
		bgBottomImg->Draw();
		creditsWindow.Draw();

		for(i=3; i >= 0; i--)
		{
			if(userInput[i].wpad->ir.valid)
				Menu_DrawImg(userInput[i].wpad->ir.x-48, userInput[i].wpad->ir.y-48,
					96, 96, pointer[i]->GetImage(), userInput[i].wpad->ir.angle, 1, 1, 255);
			DoRumble(i);
		}

		Menu_Render();

		for(i=0; i < 4; i++)
		{
			if(userInput[i].wpad->btns_d || userInput[i].pad.btns_d)
				exit = true;
		}
		usleep(THREAD_SLEEP);
	}
	for(i=0; i < 4; i++)
	{
		userInput[i].wpad->btns_d = 0;
		userInput[i].pad.btns_d = 0;
	}
	for(i=0; i < numEntries; i++)
		delete txt[i];
}

//----------------------------------------------------------------------------
// MENU - MenuGameSelection
//----------------------------------------------------------------------------
static int MenuGameSelection()
{
	int menu = MENU_NONE;
	int i;

	GuiText titleTxt(APPNAME, 28, (GXColor){255, 255, 255, 255});
	titleTxt.SetAlignment(ALIGN_LEFT, ALIGN_TOP);
	titleTxt.SetPosition(40,50);

	GuiSound btnSoundOver(button_over_pcm, button_over_pcm_size, SOUND_PCM);
	GuiSound btnSoundClick(button_click_pcm, button_click_pcm_size, SOUND_PCM);
	GuiImageData btnOutline(button_png);
	GuiImageData btnOutlineOver(button_over_png);

	GuiTrigger trigA;
	trigA.SetSimpleTrigger(-1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A);
	GuiTrigger trigHome;
	trigHome.SetButtonOnlyTrigger(-1, WPAD_BUTTON_HOME | WPAD_CLASSIC_BUTTON_HOME, 0);

	GuiText settingsBtnTxt("Settings", 24, (GXColor){0, 0, 0, 255});
	settingsBtnTxt.SetWrap(true, btnOutline.GetWidth()-30);
	GuiImage settingsBtnImg(&btnOutline);
	GuiImage settingsBtnImgOver(&btnOutlineOver);
	GuiButton settingsBtn(btnOutline.GetWidth(), btnOutline.GetHeight());
	settingsBtn.SetAlignment(ALIGN_LEFT, ALIGN_BOTTOM);
	settingsBtn.SetPosition(100, -35);
	settingsBtn.SetLabel(&settingsBtnTxt);
	settingsBtn.SetImage(&settingsBtnImg);
	settingsBtn.SetImageOver(&settingsBtnImgOver);
	settingsBtn.SetSoundOver(&btnSoundOver);
	settingsBtn.SetSoundClick(&btnSoundClick);
	settingsBtn.SetTrigger(&trigA);
	settingsBtn.SetEffectGrow();

	GuiText exitBtnTxt("Exit", 24, (GXColor){0, 0, 0, 255});
	exitBtnTxt.SetWrap(true, btnOutline.GetWidth()-30);
	GuiImage exitBtnImg(&btnOutline);
	GuiImage exitBtnImgOver(&btnOutlineOver);
	GuiButton exitBtn(btnOutline.GetWidth(), btnOutline.GetHeight());
	exitBtn.SetAlignment(ALIGN_RIGHT, ALIGN_BOTTOM);
	exitBtn.SetPosition(-100, -35);
	exitBtn.SetLabel(&exitBtnTxt);
	exitBtn.SetImage(&exitBtnImg);
	exitBtn.SetImageOver(&exitBtnImgOver);
	exitBtn.SetSoundOver(&btnSoundOver);
	exitBtn.SetSoundClick(&btnSoundClick);
	exitBtn.SetTrigger(&trigA);
	exitBtn.SetTrigger(&trigHome);
	exitBtn.SetEffectGrow();

	GuiWindow buttonWindow(screenwidth, screenheight);
	buttonWindow.Append(&settingsBtn);
	buttonWindow.Append(&exitBtn);

	GuiFileBrowser gameBrowser(308, 268);
	gameBrowser.SetAlignment(ALIGN_RIGHT, ALIGN_TOP);
	gameBrowser.SetPosition(-12, 98);
	ResetBrowser();

	HaltGui();

	mainWindow->Append(&titleTxt);
	mainWindow->Append(&gameBrowser);
	mainWindow->Append(&buttonWindow);

	ResumeGui();

	selectLoadedFile = 1;
	OpenGameList();
	gameBrowser.ResetState();
	gameBrowser.fileList[0]->SetState(STATE_SELECTED);
	gameBrowser.TriggerUpdate();

	while(menu == MENU_NONE)
	{
		usleep(THREAD_SLEEP);
		if(selectLoadedFile == 2)
		{
			selectLoadedFile = 0;
			mainWindow->ChangeFocus(&gameBrowser);
			gameBrowser.TriggerUpdate();
		}
		for(i=0; i < FILE_PAGESIZE; i++)
		{
			if(gameBrowser.fileList[i]->GetState() == STATE_CLICKED)
			{
				gameBrowser.fileList[i]->ResetState();
				if(browserList[browser.selIndex].isdir)
				{
					if(BrowserChangeFolder())
					{
						gameBrowser.ResetState();
						gameBrowser.fileList[0]->SetState(STATE_SELECTED);
						gameBrowser.TriggerUpdate();
					}
					else
					{
						menu = MENU_GAMESELECTION;
						break;
					}
				}
				else
				{
					ShutoffRumble();
					mainWindow->SetState(STATE_DISABLED);
//					if(BrowserLoadFile())
//						menu = MENU_EXIT;
//					else
						mainWindow->SetState(STATE_DEFAULT);
				}
			}
		}
		if(settingsBtn.GetState() == STATE_CLICKED)
			menu = MENU_SETTINGS;
		else if(exitBtn.GetState() == STATE_CLICKED)
			ExitRequested = 1;
	}
	HaltParseThread();
	HaltGui();
	ResetBrowser();
	mainWindow->Remove(&titleTxt);
	mainWindow->Remove(&buttonWindow);
	mainWindow->Remove(&gameBrowser);
	return menu;
}

//----------------------------------------------------------------------------
// MENU - MenuSettings
//----------------------------------------------------------------------------
static int MenuSettings()
{
	int menu = MENU_NONE;
	int ret;
	int i = 0;
	bool firstRun = true;
	OptionList options;
	sprintf(options.name[i++], "Auto Load");
	sprintf(options.name[i++], "Auto Save");
	sprintf(options.name[i++], "Load Device");
	sprintf(options.name[i++], "Save Device");
	sprintf(options.name[i++], "Rom Folder");
	sprintf(options.name[i++], "Save Folder");
	sprintf(options.name[i++], "Cover Folder");
	sprintf(options.name[i++], "Music Volume");
	sprintf(options.name[i++], "SFX Volume");
	sprintf(options.name[i++], "Rumble");
	options.length = i;

	GuiText titleTxt("Settings", 28, (GXColor){255, 255, 255, 255});
	titleTxt.SetAlignment(ALIGN_LEFT, ALIGN_TOP);
	titleTxt.SetPosition(50,50);

	GuiSound btnSoundOver(button_over_pcm, button_over_pcm_size, SOUND_PCM);
	GuiSound btnSoundClick(button_click_pcm, button_click_pcm_size, SOUND_PCM);
	GuiImageData btnOutline(button_png);
	GuiImageData btnOutlineOver(button_over_png);

	GuiTrigger trigA;
	trigA.SetSimpleTrigger(-1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A);

	GuiText backBtnTxt("Back", 22, (GXColor){0, 0, 0, 255});
	GuiImage backBtnImg(&btnOutline);
	GuiImage backBtnImgOver(&btnOutlineOver);
	GuiButton backBtn(btnOutline.GetWidth(), btnOutline.GetHeight());
	backBtn.SetAlignment(ALIGN_LEFT, ALIGN_BOTTOM);
	backBtn.SetPosition(100, -35);
	backBtn.SetLabel(&backBtnTxt);
	backBtn.SetImage(&backBtnImg);
	backBtn.SetImageOver(&backBtnImgOver);
	backBtn.SetSoundOver(&btnSoundOver);
	backBtn.SetSoundClick(&btnSoundClick);
	backBtn.SetTrigger(&trigA);
	backBtn.SetEffectGrow();

	GuiOptionBrowser optionBrowser(552, 248, &options);
	optionBrowser.SetPosition(0, 108);
	optionBrowser.SetAlignment(ALIGN_CENTRE, ALIGN_TOP);
	optionBrowser.SetCol2Position(185);

	HaltGui();

	GuiWindow w(screenwidth, screenheight);
	w.Append(&backBtn);
	mainWindow->Append(&optionBrowser);
	mainWindow->Append(&w);
	mainWindow->Append(&titleTxt);
	ResumeGui();

	while(menu == MENU_NONE)
	{
		usleep(THREAD_SLEEP);

		ret = optionBrowser.GetClickedOption();

		switch (ret)
		{
			case 0:
				Settings.AutoLoad++;
				if (Settings.AutoLoad > 3)
					Settings.AutoLoad = 0;
				break;

			case 1:
				Settings.AutoSave++;
				if (Settings.AutoSave > 3)
					Settings.AutoSave = 0;
				break;

			case 2:
				Settings.LoadMethod++;
				break;

			case 3:
				Settings.SaveMethod++;
				break;

			case 4:
				OnScreenKeyboard(Settings.LoadFolder, 256);
				break;

			case 5:
				OnScreenKeyboard(Settings.SaveFolder, 256);
				break;

			case 6:
				OnScreenKeyboard(Settings.CoverFolder, 256);
				break;

			case 7:
				Settings.MusicVolume += 10;
				break;

			case 8:
				Settings.SFXVolume += 10;
				break;

			case 9:
				Settings.Rumble ^= 1;
				break;
		}

		if(ret >= 0 || firstRun)
		{
			firstRun = false;

			// saving to DVD is impossible
			if(Settings.SaveMethod == DEVICE_DVD)
				Settings.SaveMethod++;

			// correct load/save methods out of bounds
			if(Settings.LoadMethod > 3)
				Settings.LoadMethod = 0;
			if(Settings.SaveMethod > 3)
				Settings.SaveMethod = 0;

			// Volume can't be more than 100%
			if(Settings.MusicVolume > 100)
				Settings.MusicVolume = 0;
			if(Settings.SFXVolume > 100)
				Settings.SFXVolume = 0;

			// Set new BGM volume
			bgMusic->SetVolume(Settings.MusicVolume);

			if (Settings.AutoLoad == 0) sprintf (options.value[0],"Off");
			else if (Settings.AutoLoad == 1) sprintf (options.value[0],"FLASH");
			else if (Settings.AutoLoad == 2) sprintf (options.value[0],"EEPROM");
			else if (Settings.AutoLoad == 3) sprintf (options.value[0],"Snapshot");

			if (Settings.AutoSave == 0) sprintf (options.value[1],"Off");
			else if (Settings.AutoSave == 1) sprintf (options.value[1],"FLASH");
			else if (Settings.AutoSave == 2) sprintf (options.value[1],"EEPROM");
			else if (Settings.AutoSave == 3) sprintf (options.value[1],"Snapshot");

			if (Settings.LoadMethod == DEVICE_AUTO) sprintf (options.value[2],"Auto Detect");
			else if (Settings.LoadMethod == DEVICE_SD) sprintf (options.value[2],"SD");
			else if (Settings.LoadMethod == DEVICE_USB) sprintf (options.value[2],"USB");
			else if (Settings.LoadMethod == DEVICE_DVD) sprintf (options.value[2],"DVD");

			if (Settings.SaveMethod == DEVICE_AUTO) sprintf (options.value[3],"Auto Detect");
			else if (Settings.SaveMethod == DEVICE_SD) sprintf (options.value[3],"SD");
			else if (Settings.SaveMethod == DEVICE_USB) sprintf (options.value[3],"USB");

			snprintf (options.value[4], 256, "%s", Settings.LoadFolder);
			snprintf (options.value[5], 256, "%s", Settings.SaveFolder);
			snprintf (options.value[6], 256, "%s", Settings.CoverFolder);

			if(Settings.MusicVolume > 0) sprintf(options.value[7], "%d%%", Settings.MusicVolume);
			else sprintf(options.value[7], "Mute");

			if(Settings.SFXVolume > 0) sprintf(options.value[8], "%d%%", Settings.SFXVolume);
			else sprintf(options.value[8], "Mute");

			if (Settings.Rumble == 1) sprintf (options.value[9], "Enabled");
			else sprintf (options.value[9], "Disabled");

			optionBrowser.TriggerUpdate();
		}

		if(backBtn.GetState() == STATE_CLICKED)
		{
			menu = MENU_GAMESELECTION;
		}
	}

	HaltGui();

	mainWindow->Remove(&optionBrowser);
	mainWindow->Remove(&w);
	mainWindow->Remove(&titleTxt);

	return menu;
}

//----------------------------------------------------------------------------
// MENU - MainMenu
//----------------------------------------------------------------------------
void MainMenu(int menu)
{
	int currentMenu = menu;
	lastMenu = MENU_NONE;

	pointer[0] = new GuiImageData(player1_point_png);
	pointer[1] = new GuiImageData(player2_point_png);
	pointer[2] = new GuiImageData(player3_point_png);
	pointer[3] = new GuiImageData(player4_point_png);

	mainWindow = new GuiWindow(screenwidth, screenheight);

	bgImg = new GuiImage(screenwidth, screenheight, (GXColor){100, 100, 105, 255});
	bgImg->ColorStripe(30);
	mainWindow->Append(bgImg);

	GuiTrigger trigA;
	trigA.SetSimpleTrigger(-1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A);

	GuiSound btnSoundOver(button_over_pcm, button_over_pcm_size, SOUND_PCM);
	GuiSound btnSoundClick(button_click_pcm, button_click_pcm_size, SOUND_PCM);

	GuiImageData bgTop(bg_top_png);
	bgTopImg = new GuiImage(&bgTop);
	bgTopImg->SetAlignment(ALIGN_LEFT, ALIGN_TOP);

	GuiImageData bgBottom(bg_bottom_png);
	bgBottomImg = new GuiImage(&bgBottom);
	bgBottomImg->SetAlignment(ALIGN_LEFT, ALIGN_BOTTOM);

	GuiImageData logo(logo_png);
	GuiImage logoImg(&logo);
	GuiImageData logoOver(logo_over_png);
	GuiImage logoImgOver(&logoOver);
	btnLogo = new GuiButton(logoImg.GetWidth(), logoImg.GetHeight());
	btnLogo->SetAlignment(ALIGN_RIGHT, ALIGN_TOP);
	btnLogo->SetPosition(-12, 30);
	btnLogo->SetImage(&logoImg);
	btnLogo->SetImageOver(&logoImgOver);
	btnLogo->SetSoundOver(&btnSoundOver);
	btnLogo->SetSoundClick(&btnSoundClick);
	btnLogo->SetTrigger(&trigA);
	btnLogo->SetUpdateCallback(WindowCredits);

	version = new GuiText("v" APPVERSION, 18, (GXColor){255, 255, 255, 255});
	version->SetAlignment(ALIGN_RIGHT, ALIGN_BOTTOM);
	version->SetPosition(-20, -36);

	mainWindow->Append(bgTopImg);
	mainWindow->Append(bgBottomImg);
	mainWindow->Append(btnLogo);
	mainWindow->Append(version);

	if(currentMenu == MENU_GAMESELECTION)
		ResumeGui();

	// Load preferences
	if(!LoadPrefs())
		SavePrefs(SILENT);

	#ifndef NO_SOUND
	bgMusic = new GuiSound(bg_music_ogg, bg_music_ogg_size, SOUND_OGG);
	bgMusic->SetVolume(Settings.MusicVolume);
	bgMusic->SetLoop(true);
	if(currentMenu == MENU_GAMESELECTION) bgMusic->Play();

	enterSound = new GuiSound(enter_ogg, enter_ogg_size, SOUND_OGG);
	enterSound->SetVolume(Settings.SFXVolume);

	exitSound = new GuiSound(exit_ogg, exit_ogg_size, SOUND_OGG);
	exitSound->SetVolume(Settings.SFXVolume);
	#endif

//	while(currentMenu != MENU_EXIT || !ROMLoaded)
	while(currentMenu != MENU_EXIT)
	{
		switch (currentMenu)
		{
			case MENU_GAMESELECTION:
				currentMenu = MenuGameSelection();
				break;
			case MENU_SETTINGS:
				currentMenu = MenuSettings();
				break;
			default: // unrecognized menu
				currentMenu = MenuGameSelection();
				break;
		}
		lastMenu = currentMenu;
		usleep(THREAD_SLEEP);
	}

	ShutoffRumble();

	while(MenuRequested())
		usleep(THREAD_SLEEP);

	CancelAction();
	HaltGui();

	if(updatethread != LWP_THREAD_NULL)
		LWP_JoinThread(updatethread, NULL);

	bgMusic->Stop();
	delete bgMusic;
	delete enterSound;
	delete exitSound;
	delete btnLogo;
	delete bgImg;
	delete bgTopImg;
	delete bgBottomImg;
	delete version;
	delete mainWindow;

	delete pointer[0];
	delete pointer[1];
	delete pointer[2];
	delete pointer[3];

	mainWindow = NULL;
}
